/// <summary>
///   新版本算法，取消部分单字母后缀，新增三字母后缀
/// </summary>

using UnityEngine;

namespace GameHelper.Tools
{
    using System;
    using System.Text;

    /*
      int      类型的最大值是:2147483647
      uint     类型的最大值是:4294967295
      byte     类型的最大值是:255
      sbyte    类型的最大值是:127
      short    类型的最大值是:32767
      ushort   类型的最大值是:65535
      long     类型的最大值是:9223372036854775807
      long     类型的最小值是:-9223372036854775808
      ulong    类型的最大值是:18446744073709551615
      ulong    类型的最小值是:0
      float    类型的最大值是:3.402823E+38
      double   类型的最*值是:1.79769313486232E+308
      decimal  类型的最大值是:79228162514264337593543950335
      int      类型的最小值是:-2147483648
      uint     类型的最小值是:0
      byte     类型的最小值是:0
      sbyte    类型的最小值是:-128
      short    类型的最小值是:-32768
      ushort   类型的最小值是:0
      float    类型的最小值是:-3.402823E+38
      double   类型的最小值是:-1.79769313486232E+308
      decimal  类型的最小值是:-79228162514264337593543950335
    */

    public static class HugeNumHelper
    {
        public static bool isFixPrecision = false;
        public static readonly char[] ASCII_LETTERS = new char[]{
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
        };

        public static readonly char[] ASCII_DIGITS = new char[] {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
        };

        // 安全值：在此范围内进行加减法不会出现long型溢出问题
        public const long SAFE_MAX = 99999999999999999L; // 4611686018427387903L
        public const long SAFE_MIN = -99999999999999999L; // -4611686018427387903L

        // long 最高支持10^18
        public const long EXP_18 = 1000000000000000000L;
        public const long EXP_17 = 100000000000000000L;
        public const long EXP_16 = 10000000000000000L;
        public const long EXP_15 = 1000000000000000L;
        public const long EXP_14 = 100000000000000L;
        public const long EXP_13 = 10000000000000L;
        public const long EXP_12 = 1000000000000L;
        public const long EXP_11 = 100000000000L;
        public const long EXP_10 = 10000000000L;
        public const long EXP_09 = 1000000000L;
        public const long EXP_08 = 100000000L;
        public const long EXP_07 = 10000000L;
        public const long EXP_06 = 1000000L;
        public const long EXP_05 = 100000L;
        public const long EXP_04 = 10000L;
        public const long EXP_03 = 1000L;
        public const long EXP_02 = 100L;
        public const long EXP_01 = 10L;
        public const long EXP_00 = 1L;

        public static readonly long[] POW_OF_10 = new long[] {
            1L,
            10L,
            100L,
            1000L,
            10000L,
            100000L,
            1000000L,
            10000000L,
            100000000L,
            1000000000L,
            10000000000L,
            100000000000L,
            1000000000000L,
            10000000000000L,
            100000000000000L,
            1000000000000000L,
            10000000000000000L,
            100000000000000000L,
            1000000000000000000L,
        };

        public static readonly double[] ONE_OF_TENS = new double[] {
            1.0 / 1.0,
            1.0 / 10.0,
            1.0 / 100.0,
            1.0 / 1000.0,
            1.0 / 10000.0,
            1.0 / 100000.0,
            1.0 / 1000000.0,
            1.0 / 10000000.0,
            1.0 / 100000000.0,
            1.0 / 1000000000.0,
            1.0 / 10000000000.0,
            1.0 / 100000000000.0,
            1.0 / 1000000000000.0,
            1.0 / 10000000000000.0,
            1.0 / 100000000000000.0,
            1.0 / 1000000000000000.0,
            1.0 / 10000000000000000.0,
            1.0 / 100000000000000000.0,
            1.0 / 1000000000000000000.0,
        };

        public static readonly double[] POW_OF_10_DOUBLE = new double[] {
            1e+0, // Pow(10.0, 0)
            1e+1, // Pow(10.0, 1)
            1e+2, // Pow(10.0, 2)
            1e+3,
            1e+4,
            1e+5,
            1e+6,
            1e+7,
            1e+8,
            1e+9,
            1e+10,
            1e+11,
            1e+12,
            1e+13,
            1e+14,
            1e+15,
            1e+16,
            1e+17,
            1e+18,
            1e+19,
            1e+20,
            1e+21,
            1e+22,
            1e+23,
            1e+24,
            1e+25,
            1e+26,
            1e+27,
            1e+28,
            1e+29,
            1e+30,
            1e+31,
            1e+32,
            1e+33,
            1e+34,
            1e+35,
            1e+36,
            1e+37,
            1e+38,
            1e+39,
            1e+40,
        };

        public static bool ChineseSymbol = true;
        public static readonly int LOG10_OF_MAXLONG = 18;

        // 指数转基数
        public static readonly long[] EXP_TO_VAL = new long[] {
            EXP_00, EXP_01, EXP_02, EXP_03, EXP_04, EXP_05, EXP_06,
            EXP_07, EXP_08, EXP_09, EXP_10, EXP_11, EXP_12, EXP_13,
            EXP_14, EXP_15, EXP_16, EXP_17, EXP_18
        };

        // // 有效的后缀字符
        // public static readonly char[] VALID_SUFFIX_CHARS = new char[] {
        //     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
        //     'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        //     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
        //     'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        // };

        public static readonly char[] VALID_LOWER_SUFFIX_CHARS = new char[] {
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        };

        public static readonly char[] VALID_UPPER_SUFFIX_CHARS = new char[] {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        };
        // 基础进制符号 1000
        // public static readonly char[] SINGLE_UNIT_SYMBOL = new char[] { ' ', 'k', 'm', 'b', 't', 'q', 'Q', 's', 'S', 'o', 'n', 'd', 'u', 'D', 'T' };
        public static readonly char[] SINGLE_UNIT_SYMBOL = new char[] { ' ', 'k', 'm', 'b', 't' };

        public static readonly string[] SINGLE_UNIT_SYMBOL_CHINESE = new string[] { " ", "万", "亿" };
        // public static readonly int MAX_EXP_OF_SINGLE = SINGLE_UNIT_SYMBOL.Length * 3; // 单字符最大指数
        // public static readonly int MAX_EXP_RANGE_OF_BINARY = 26 * 26 * 3; // 双字符指数跨度
        // public static readonly int MAX_EXP_RANGE_OF_TRIPLE = 26 * 26 * 26 * 3; // 三字符指数跨度

        /// <summary>
        ///   不同形式的后缀的指数范围
        /// </summary>
        public static readonly int[] SUFFIX_EXP_RANGES;

        // 扩展进制符号 10
        public static readonly char[] EXTRA_UNIT_SYMBOL = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        };
        public static readonly int EXTRA_UNIT_NUM = EXTRA_UNIT_SYMBOL.Length;

        // public static readonly string[] NORMAL_UNIT_SUFFIX = new string[] { "", "k", "m", "b", "t", "q", "Q", "s", "S", "o", "n", "d", "u", "D", "T" };
        public static readonly string[] NORMAL_UNIT_SUFFIX = new string[] { "", "k", "m", "b", "t" };
        public static readonly string[] EXTRA_UNIT_SUFFIX = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
            "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
        };

        static HugeNumHelper()
        {
            SUFFIX_EXP_RANGES = new int[10];
            if (ChineseSymbol)
            {
                SUFFIX_EXP_RANGES[0] = 4;
            }
            else
            {
                SUFFIX_EXP_RANGES[0] = 3;
            }
            SUFFIX_EXP_RANGES[1] = 3 + (SINGLE_UNIT_SYMBOL.Length - 2) * 3;
            // 双字符小写   
            SUFFIX_EXP_RANGES[2] = SUFFIX_EXP_RANGES[1] + 3;
            SUFFIX_EXP_RANGES[3] = SUFFIX_EXP_RANGES[2] + (26 * 26 - 1) * 3;
            // 双字符大写
            SUFFIX_EXP_RANGES[4] = SUFFIX_EXP_RANGES[3] + 3;
            SUFFIX_EXP_RANGES[5] = SUFFIX_EXP_RANGES[4] + (26 * 26 - 1) * 3;
            // 三字符小写
            SUFFIX_EXP_RANGES[6] = SUFFIX_EXP_RANGES[5] + 3;
            SUFFIX_EXP_RANGES[7] = SUFFIX_EXP_RANGES[6] + (26 * 26 * 26 - 1) * 3;
            // 三字符大写
            SUFFIX_EXP_RANGES[8] = SUFFIX_EXP_RANGES[7] + 3;
            SUFFIX_EXP_RANGES[9] = SUFFIX_EXP_RANGES[8] + (26 * 26 * 26 - 1) * 3;
        }

        public static bool IsValidNormUnitSymbol(char c)
        {
            if (c == ' ')
                return false;
            return Array.IndexOf(SINGLE_UNIT_SYMBOL, c) >= 0;
        }

        public static bool IsValidExtraUnitSymbol(char c)
        {
            return Array.IndexOf(EXTRA_UNIT_SYMBOL, c) >= 0;
        }

        public static bool IsValidExtraUnitSymbol(string s)
        {
            for (int i = s.Length - 1; i >= 0; i--)
            {
                if (!IsValidExtraUnitSymbol(s[i]))
                    return false;
            }
            return true;
        }

        // public static bool IsValidSuffix(string suffix) {
        //     if (string.IsNullOrEmpty(suffix))
        //         return false;
        //     var len = suffix.Length;
        //     if (1 == len) {
        //     }else if (2 == len) {
        //     }else if (3 == len) {
        //     }
        //     return false;
        // }

        /// <summary>
        ///   十进制转26进制
        /// </summary>
        public static string DecimalToBase26(int dec, bool upperCase, int len)
        {
            if (0 == dec)
            {
                if (upperCase)
                {
                    if (3 == len) return "AAA";
                    else if (2 == len) return "AA";
                    return "A";
                }
                else
                {
                    if (3 == len) return "aaa";
                    else if (2 == len) return "aa";
                    return "a";
                }
            }
            var sb = new StringBuilder();
            while (dec != 0)
            {
                if (upperCase)
                {
                    sb.Insert(0, VALID_UPPER_SUFFIX_CHARS[dec % 26]);
                }
                else
                {
                    sb.Insert(0, VALID_LOWER_SUFFIX_CHARS[dec % 26]);
                }
                dec = dec / 26;
            }
            while (sb.Length < len)
            {
                sb.Insert(0, upperCase ? VALID_UPPER_SUFFIX_CHARS[0] : VALID_LOWER_SUFFIX_CHARS[0]);
            }
            return sb.ToString();
        }

        /// <summary>
        ///   指数转后缀
        /// </summary>
        public static string ExponentToSuffix(int exp, out int remains)
        {
            if (exp < SUFFIX_EXP_RANGES[0])
            { // 无字符
                remains = 0;
                return "";
            }

            if (ChineseSymbol)
            {
                if (exp < SUFFIX_EXP_RANGES[1])
                { // 无字符
                    var delta = exp - SUFFIX_EXP_RANGES[0];
                    remains = delta % 4;
                    return SINGLE_UNIT_SYMBOL_CHINESE[delta / 4 + 1].ToString();
                }
                if (exp < SUFFIX_EXP_RANGES[2])
                { // 单字符
                    var delta = exp - 3;
                    remains = delta % 3;
                    return SINGLE_UNIT_SYMBOL[delta / 3 + 1].ToString();
                }
            }
            else
            {
                if (exp < SUFFIX_EXP_RANGES[2])
                { // 单字符
                    var delta = exp - SUFFIX_EXP_RANGES[0];
                    remains = delta % 3;
                    return SINGLE_UNIT_SYMBOL[delta / 3 + 1].ToString();
                }
            }
            if (exp < SUFFIX_EXP_RANGES[4])
            { // 双字符小写
                var delta = exp - SUFFIX_EXP_RANGES[2];
                remains = delta % 3;
                return DecimalToBase26(delta / 3, false, 2);
            }
            if (exp < SUFFIX_EXP_RANGES[6])
            { // 双字符大写
                var delta = exp - SUFFIX_EXP_RANGES[4];
                remains = delta % 3;
                return DecimalToBase26(delta / 3, true, 2);
            }
            if (exp < SUFFIX_EXP_RANGES[8])
            { // 三字符小写
                var delta = (exp - SUFFIX_EXP_RANGES[6]);
                remains = delta % 3;
                return DecimalToBase26(delta / 3, false, 3);
            }
            if (exp < (SUFFIX_EXP_RANGES[9] + 3))
            { // 三字符大写
                var delta = exp - SUFFIX_EXP_RANGES[8];
                remains = delta % 3;
                return DecimalToBase26(delta / 3, true, 3);
            }
            remains = 0;
            return "$$$";
        }

        /// <summary>
        ///   后缀转指数, 无效时返回false
        /// </summary>
        public static bool SuffixToExponent(string suffix, out int exp)
        {
            bool valid = false;
            exp = 0;
            do
            {
                if (string.IsNullOrEmpty(suffix))
                    break;
                var len = suffix.Length;
                if (1 == len)
                { // 单字符后缀
                    var index = Array.IndexOf(SINGLE_UNIT_SYMBOL, suffix[0]);
                    if (index >= 0)
                    {
                        valid = true;
                        exp = index * 3;
                    }
                }
                else if (2 == len || 3 == len)
                { // [2, 3]字符后缀
                    var suffixCase = 0;  // 1: 小写；2: 大写
                    // 三位十进制
                    var decimalNumber = new int[] { 0, 0, 0 };
                    var decimalNumberSize = decimalNumber.Length;
                    valid = true;
                    // 遍历后缀字符，并将他们转成十进制
                    for (int i = 0; i < len && valid; i++)
                    {
                        var c = suffix[i];
                        do
                        {
                            var charCase = 0;
                            var charIndex = Array.IndexOf(VALID_LOWER_SUFFIX_CHARS, c);
                            if (charIndex < 0)
                            {
                                charIndex = Array.IndexOf(VALID_UPPER_SUFFIX_CHARS, c);
                                if (charIndex < 0)
                                {
                                    valid = false;
                                    break;
                                }
                                charCase = 2;
                            }
                            else
                            {
                                charCase = 1;
                            }
                            if (charCase != suffixCase)
                            {
                                if (0 == suffixCase)
                                {
                                    suffixCase = charCase;
                                }
                                else
                                {
                                    valid = false;
                                    break;
                                }
                            }
                            decimalNumber[i + decimalNumberSize - len] = charIndex;
                        } while (false);
                    }
                    if (!valid)
                        break;
                    // 26进制
                    var suffixNum = (decimalNumber[0] * 26 * 26) + (decimalNumber[1] * 26) + decimalNumber[2];
                    if (len == 2)
                    {
                        if (1 == suffixCase)
                        {
                            exp = SUFFIX_EXP_RANGES[2] + (suffixNum) * 3;
                        }
                        else
                        {
                            exp = SUFFIX_EXP_RANGES[4] + (suffixNum) * 3;
                        }
                    }
                    else
                    {
                        if (1 == suffixCase)
                        {
                            exp = SUFFIX_EXP_RANGES[6] + (suffixNum) * 3;
                        }
                        else
                        {
                            exp = SUFFIX_EXP_RANGES[8] + (suffixNum) * 3;
                        }
                    }
                }
                else
                {
                    break;
                }
            } while (false);
            return valid;
        }

        public static bool IsLetter(char c)
        {
            return Array.IndexOf(ASCII_LETTERS, c) >= 0;
        }

        public static bool StringEndsWithLetter(string s)
        {
            if (string.IsNullOrEmpty(s))
                return false;
            return IsLetter(s[s.Length - 1]);
        }

        public static int ExpOf10(double value)
        {
            if (0.0 == value)
            {
                throw new Exception("Exp of 0 undefined!");
            }
            // if (value < 0)
            //     value = -value;
            // if (value <= POW_OF_10_DOUBLE[0])
            //     return 0;
            // if (value <= POW_OF_10_DOUBLE[1])
            //     return 1;
            // if (value <= POW_OF_10_DOUBLE[2])
            //     return 2;
            // if (value <= POW_OF_10_DOUBLE[3])
            //     return 3;
            // if (value <= POW_OF_10_DOUBLE[4])
            //     return 4;
            // if (value <= POW_OF_10_DOUBLE[5])
            //     return 5;
            // if (value <= POW_OF_10_DOUBLE[6])
            //     return 6;
            // if (value <= POW_OF_10_DOUBLE[7])
            //     return 7;
            // if (value <= POW_OF_10_DOUBLE[8])
            //     return 8;
            // if (value <= POW_OF_10_DOUBLE[9])
            //     return 9;
            // if (value <= POW_OF_10_DOUBLE[10])
            //     return 10;
            for (int i = 0; i < POW_OF_10_DOUBLE.Length; i++)
            {
                if (value <= POW_OF_10_DOUBLE[i])
                {
                    return i;
                }
            }
            throw new Exception("Exp of 10 failed");
        }

        /// <summary>
        ///   计算指数
        /// </summary>
        public static int Log10(long significand)
        {
            if (significand == long.MinValue)
                return 18;
            // 注意：-long.MinValue数据溢出
            var signif_ = significand > 0 ? significand : -significand;
            if (signif_ >= EXP_18)
            {
                return 18;
            }
            else if (signif_ >= EXP_17)
            {
                return 17;
            }
            else if (signif_ >= EXP_16)
            {
                return 16;
            }
            else if (signif_ >= EXP_15)
            {
                return 15;
            }
            else if (signif_ >= EXP_14)
            {
                return 14;
            }
            else if (signif_ >= EXP_13)
            {
                return 13;
            }
            else if (signif_ >= EXP_12)
            {
                return 12;
            }
            else if (signif_ >= EXP_11)
            {
                return 11;
            }
            else if (signif_ >= EXP_10)
            {
                return 10;
            }
            else if (signif_ >= EXP_09)
            {
                return 9;
            }
            else if (signif_ >= EXP_08)
            {
                return 8;
            }
            else if (signif_ >= EXP_07)
            {
                return 7;
            }
            else if (signif_ >= EXP_06)
            {
                return 6;
            }
            else if (signif_ >= EXP_05)
            {
                return 5;
            }
            else if (signif_ >= EXP_04)
            {
                return 4;
            }
            else if (signif_ >= EXP_03)
            {
                return 3;
            }
            else if (signif_ >= EXP_02)
            {
                return 2;
            }
            else if (signif_ >= EXP_01)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
    }

    // /// <summary>
    // ///   加减法运算结果(如果两数相差太大，会忽略一侧的值)
    // /// </summary>
    // public enum ResultState
    // {
    //     Left,
    //     Right,
    //     Both
    // }

    /// <summary>
    ///   有效显示999.999 * 10^2070, 超出的部分显示为xxx.xxx$$
    /// </summary>
    [System.Serializable]
    public struct HugeNum
    {
        #region constructors

        public static readonly HugeNum zero = new HugeNum(0, 0);
        public static readonly HugeNum one = new HugeNum(1, 0);
        public static readonly HugeNum neg_one = new HugeNum(-1, 0);

        // double转HugeNum时用，最多保留小数点后4位
        public static readonly double GOOD_NUM_MIN = (long)((double)long.MinValue / 10000.0);
        public static readonly double GOOD_NUM_MAX = (long)((double)long.MaxValue / 10000.0);

        public static readonly ulong MaxLongOfULong = (ulong)long.MaxValue;
        public static readonly double MaxLongOfDouble = (double)long.MaxValue;
        public static readonly double MinLongOfDouble = (double)long.MinValue;

        // double 精度15-16位十进制
        // 19位十进制有效位
        public long significand; // 有效位数 [-9223372036854775808, 9223372036854775807]
        public int exponent; // 指数 [-32768, 32767]

#if UNITY_EDITOR

        //[ShowInInspector, LabelText("显示数值")]
        public string ValueStr => this.ToString();

#endif

        public HugeNum(long significand, int exponent)
        {
            this.significand = significand;
            this.exponent = exponent;
            if (0 == this.significand)
                this.exponent = 0;
        }

        public HugeNum(int n) : this((long)n)
        {
            // nop
        }

        public HugeNum(uint n) : this((ulong)n)
        {
            // nop
        }

        public HugeNum(long n)
        {
            significand = n;
            exponent = 0;
            if (HugeNumHelper.isFixPrecision)
                significand = ReducePrecision(significand, exponent);
        }

        public HugeNum(ulong n)
        {
            if (n > MaxLongOfULong)
            {
                // long 和ulong最大值只相差1个十进制位
                significand = (long)(n / 10);
                exponent = 1;
                if (HugeNumHelper.isFixPrecision)
                    significand = ReducePrecision(significand, exponent);
            }
            else
            {
                significand = (long)n;
                exponent = 0;
                if (HugeNumHelper.isFixPrecision)
                    significand = ReducePrecision(significand, exponent);
            }
        }

        public HugeNum(float n) : this((double)n)
        {
            // nop
        }

        public HugeNum(double n)
        {
            significand = 0;
            exponent = 0;
            InitWith(n);
            if (HugeNumHelper.isFixPrecision)
                significand = ReducePrecision(significand, exponent);
        }

        void InitWith(double n)
        {
            if (1.0 == n)
            {
                significand = 1;
                exponent = 0;
            }
            else if (0.0 == n)
            {
                significand = 0;
                exponent = 0;
            }
            else if (double.IsNaN(n))
            {
                significand = 0;
                exponent = 0;
            }
            else if (double.IsPositiveInfinity(n))
            {
                significand = long.MaxValue;
                exponent = int.MaxValue;
            }
            else if (double.IsNegativeInfinity(n))
            {
                significand = long.MinValue;
                exponent = int.MaxValue;
            }
            else if (n > 0.0 && n <= double.Epsilon)
            {
                significand = 1;
                exponent = -300;
            }
            else
            {
                // bool isInteger = Math.Floor(n) == n;
                if (n >= GOOD_NUM_MIN && n <= GOOD_NUM_MAX)
                {
                    if (n > -1.0 && n < 1.0)
                    {
                        var sci = DoubleParser.ExtractScientificNotationParts(n);
                        significand = (long)(double.Parse(sci[0]) * 100000000000000000L);
                        exponent = int.Parse(sci[1]) - 17;
                        return;
                    }
                    else
                    {
                        significand = (long)(n * 10000.0);
                        exponent = -4;
                    }
                }
                if (0 == significand)
                {
                    // TODO: 误差比较大 
                    // 分解科学计数法，n = _significand * Math.Pow(10, _exponent); 
                    double _significand;
                    double _exponent;
                    ToScientific(n, out _significand, out _exponent);

                    significand = (long)(_significand * HugeNumHelper.EXP_17);
                    exponent = (int)_exponent - 17;

                    if (0 == significand && 0 != exponent)
                    {
                        exponent = 0;
                    }
                }
            }
        }



        public class DoubleParser
        {
            public static int GetExponent(double d)
            {
                var doubleParts = ExtractScientificNotationParts(d);
                return Convert.ToInt32(doubleParts[1]);
            }
            public static double GetMantissa(double d)
            {
                var doubleParts = ExtractScientificNotationParts(d);
                return Convert.ToDouble(doubleParts[0]);
            }
            public static string[] ExtractScientificNotationParts(double d)
            {
                var doubleParts = d.ToString(@"E17").Split('E');
                if (doubleParts.Length != 2)
                    throw new ArgumentException();
                return doubleParts;
            }
        }

        /// <summary>
        ///   科学计数法分解
        /// </summary>
        public static void ToScientific(double a, out double significand, out double exponent)
        {
            if (a == 0)
            {
                significand = 0;
                exponent = 0;
                return;
            }
            if (a > 0.0 && a <= double.Epsilon)
            {
                significand = 1;
                exponent = -300;
                return;
            }
            double b = a > 0 ? a : -a;
            exponent = (int)Math.Log10(b);
            double k = b / Math.Pow(10, exponent);

            if (k < 1) { exponent--; }
            if (k >= 10) { exponent++; }

            significand = a / Math.Pow(10.0, exponent);
        }

        void InitWith(string s)
        {
            int len = s.Length;
            int lastDigit = s.LastIndexOfAny(HugeNumHelper.ASCII_DIGITS);
            if (lastDigit >= 0)
            {
                var numStr = s.Substring(0, lastDigit + 1);
                var suffix = s.Substring(lastDigit + 1);
                double num = double.Parse(numStr);

                if (HugeNumHelper.SuffixToExponent(suffix, out int exp))
                {
                    InitWith(num);
                    this.exponent += exp;
                    return;
                }
                // invalid format
                significand = 0;
                exponent = 0;
                throw new System.FormatException();
            }
            else
            {
                significand = 0;
                exponent = 0;
                throw new System.FormatException();
            }
        }

        public HugeNum(string s)
        {
            if (string.IsNullOrEmpty(s))
            {
                significand = 0;
                exponent = 0;
            }
            else
            {
                s = s.Trim();
                if (s.IndexOf('.') >= 0)
                {
                    if (HugeNumHelper.StringEndsWithLetter(s))
                    {
                        // 解析为大数字
                        significand = 0;
                        exponent = 0;
                        InitWith(s);
                    }
                    else
                    {
                        // 解析为double
                        significand = 0;
                        exponent = 0;
                        InitWith(double.Parse(s));
                    }
                }
                else
                {
                    if (HugeNumHelper.StringEndsWithLetter(s))
                    {
                        // 解析大数字
                        significand = 0;
                        exponent = 0;
                        InitWith(s);
                    }
                    else
                    {
                        // 解析long
                        try
                        {
                            significand = long.Parse(s);
                            exponent = 0;
                        }
                        catch (OverflowException)
                        {
                            significand = 0;
                            exponent = 0;
                            // 溢出了，解析为double
                            InitWith(double.Parse(s));
                        }
                    }
                }
            }
            if (0 == significand)
                exponent = 0;
        }

        #endregion

        /// <summary>
        ///   等于1判断
        /// </summary>
        public bool IsOne()
        {
            if (1 == significand && 0 == exponent)
            {
                return true;
            }
            int exp10OfSig = HugeNumHelper.Log10(significand);
            if (HugeNumHelper.POW_OF_10[exp10OfSig] == significand)
            {
                return 0 == (exp10OfSig + exponent);
            }
            return false;
        }

        /// <summary>
        ///   判断是否为零
        /// </summary>
        public bool IsZero()
        {
            return 0L == significand;
        }

        /// <summary>
        ///   非零判断
        /// </summary>
        public bool NonZero()
        {
            return 0L != significand;
        }

        /// <summary>
        ///   正数
        /// </summary>
        public bool IsPositive()
        {
            return significand > 0L;
        }

        /// <summary>
        ///   负数
        /// </summary>
        public bool IsNegative()
        {
            return significand < 0L;
        }

        /// <summary>
        ///   求相反数
        /// </summary>
        public HugeNum Negate()
        {
            var ret = this;
            if (ret.significand == long.MinValue)
            {
                // long.MinValue直接取反溢出
                ret.significand = -(ret.significand / 10L);
                ret.exponent += 1;
            }
            else
            {
                ret.significand = -ret.significand;
            }
            return ret;
        }

        // /// <summary>
        // ///   n次方运算
        // /// </summary>
        // public HugeNum Power(uint n)
        // {
        //     if (0 == n)
        //         return HugeNum.one;
        //     var result = this;
        //     for (int i = 0; i < n - 1; i++)
        //     {
        //         result *= result;
        //     }
        //     return result;
        // }

        private static HugeNum Pow(HugeNum v, int p)
        {
            // p次方拆分成(300 X x + y)次方
            // v ^ p => (v ^ y) X ((v ^ 300) ^ x)
            //    aka: Pow(v, p) => Pow(v, y) X Pow(Pow(v, 300), x)
            int x = p / 300;
            int y = p % 300;

            // Console.WriteLine("Recalc: {0} => {1} * {2} + {3}", p, 300, x, y);
            HugeNum res = v.Pow(300).Pow(x);
            if (0 != y)
            {
                res *= v.Pow(y);
            }
            return res;
        }

        /// <summary>
        ///   x次方运算
        /// </summary>
        public HugeNum Pow(int x)
        {
            // 指数运算特例
            if (IsZero())
                return zero;
            if (0 == x)
                return one;
            if (1 == x)
                return this;

            // 转换标准科学计数法
            int sigExpo = HugeNumHelper.Log10(significand);
            int fullExpo = exponent + sigExpo;
            double normSig = (double)significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpo];

            // Console.WriteLine("x: {0}", normSig);

            double result_significand = Math.Pow(normSig, x);
            // if (double.IsNaN(result_significand)) {
            //     Console.WriteLine("NaN of pow");
            // }else if (double.IsInfinity(result_significand)) {
            //     Console.WriteLine("Infinity of pow");
            // }

            // Console.WriteLine("pow: {0}", result_significand);

            if (double.IsInfinity(result_significand) || double.IsNaN(result_significand))
            {
                // Console.WriteLine("Overflow: {0} {1} ^ {2}", this, this.DebugInfo(), x);
                // 上一步的指数运算溢出了, 将x指数运算拆分开运算
                return Pow(this, x);
            }

            // TODO: 溢出防护
            int result_exponent = x * fullExpo;

            var result = new HugeNum(result_significand);
            result.exponent += result_exponent;

            return result;
        }

        // /// <summary>
        // ///   x次方运算
        // /// </summary>
        // public HugeNum Pow(float x)
        // {
        //     // 指数运算特例
        //     if (IsZero())
        //         return zero;
        //     if (0.0f == x)
        //         return one;
        //     if (1.0f == x)
        //         return this;

        //     // 转换标准科学计数法
        //     int sigExpo = HugeNumHelper.Log10(significand);
        //     int fullExpo = exponent + sigExpo;
        //     double normSig = (double)significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpo];

        //     double result_significand = Math.Pow(normSig, x);

        //     int expInt = (int)x;
        //     int result_exponent = expInt * fullExpo;

        //     // 指数X的小数部分, 转移到结果的基数
        //     float expRemain = x - expInt;
        //     if (0.0f != expRemain)
        //     {
        //         result_significand *= Math.Pow(HugeNumHelper.POW_OF_10[exponent], expRemain);
        //     }

        //     // 当前值变成: newSig * Math.Pow(10, result.exponent)

        //     var result = new HugeNum(result_significand);
        //     result.exponent += result_exponent;

        //     return result;
        // }

        // public HugeNum Power(float n)
        // {
        //     uint intPart = (uint)n;
        //     var p = Power(intPart);
        //     if ((float)intPart == n)
        //     {
        //         return p;
        //     }
        //     var extra = Math.Pow(double x, double y)
        // }

        #region implicit conversion

        public static implicit operator HugeNum(int v)
        {
            return new HugeNum(v);
        }

        public static implicit operator HugeNum(uint v)
        {
            return new HugeNum(v);
        }

        public static implicit operator HugeNum(long v)
        {
            return new HugeNum(v);
        }

        public static implicit operator HugeNum(ulong v)
        {
            return new HugeNum(v);
        }

        public static implicit operator HugeNum(float v)
        {
            return new HugeNum(v);
        }

        public static implicit operator HugeNum(double v)
        {
            return new HugeNum(v);
        }

        #endregion

        #region operators

        public static bool Greater(HugeNum a, HugeNum b)
        {
            if (a.ToString().Equals(b.ToString()))
            {
                return false;
            }
            else
            {
                return a > b;
            }
        }
        public static bool GreaterAndEqual(HugeNum a, HugeNum b)
        {
            return a.ToString().Equals(b.ToString()) || a >= b;
            // if (a.ToString().Equals(b.ToString()))
            // {
            //     return false;
            // }
            // else
            // {
            //     return a > b;
            // }
        }
        public static bool Less(HugeNum a, HugeNum b)
        {
            if (a.ToString().Equals(b.ToString()))
            {
                return false;
            }
            else
            {
                return a < b;
            }
        }

        public static bool Equal(HugeNum a, HugeNum b)
        {
            if (a.ToString().Equals(b.ToString()))
            {
                return true;
            }
            else
            {
                return a == b;
            }
        }

        public static HugeNum Division(HugeNum a, HugeNum b)
        {
            if (a.ToString().Equals(b.ToString()))
            {
                return 1;
            }
            else
            {
                return a / b;
            }
        }
        /// <summary>
        ///  取相反数
        /// </summary>
        public static HugeNum operator -(HugeNum a)
        {
            // var ret = new HugeNum();
            // ret.significand = -a.significand;
            // ret.exponent = a.exponent;
            // return ret;
            return a.Negate();
        }

        /// <summary>
        ///  公式转换: aX10^m + bX10^n = (a + b * 10^(n - m)) * 10^m
        /// </summary>
        public static HugeNum operator +(HugeNum a, HugeNum b)
        {
            return Add(a, b, out bool changed);

            // if (a.significand == 0 && b.significand != 0)
            // {
            //     return b;
            // }
            // else if (a.significand != 0 && b.significand == 0)
            // {
            //     return a;
            // }
            // else if (a.significand == 0 && b.significand == 0)
            // {
            //     return new HugeNum { significand = 0, exponent = 0 };
            // }
            // int sigExpoA = HugeNumHelper.Log10(a.significand);
            // int fullExpoA = a.exponent + sigExpoA;
            // int sigExpoB = HugeNumHelper.Log10(b.significand);
            // int fullExpoB = b.exponent + sigExpoB;

            // // 安全加法
            // if (fullExpoA >= 0 && fullExpoA <= 17 && a.exponent >= 0 && fullExpoB >= 0 && fullExpoB <= 17 && b.exponent >= 0)
            // {
            //     long va = a.significand * HugeNumHelper.POW_OF_10[a.exponent];
            //     long vb = b.significand * HugeNumHelper.POW_OF_10[b.exponent];
            //     return new HugeNum(va + vb);
            // }

            // double valueA = (double)a.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoA];
            // double valueB = (double)b.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoB];
            // int expDiff = fullExpoB - fullExpoA;

            // var ret = new HugeNum();
            // if (expDiff >= 18)
            // {
            //     // 加号两边数值相差太大
            //     ret.InitWith(valueB * HugeNumHelper.EXP_17);
            //     ret.exponent += fullExpoA - 17 + expDiff;
            // }
            // else if (expDiff <= -18)
            // {
            //     ret.InitWith(valueA);
            //     ret.exponent += fullExpoA;
            // }
            // else
            // {
            //     // TODO: 精度损失严重
            //     ret.InitWith(valueA + valueB * Math.Pow(10.0f, expDiff));
            //     ret.exponent += fullExpoA;
            // }
            // return ret;
        }

        public static HugeNum operator -(HugeNum a, HugeNum b)
        {
            return Subtract(a, b, out bool changed);
            // if (a.significand == 0 && b.significand != 0)
            // {
            //     return -b;
            // }
            // else if (a.significand != 0 && b.significand == 0)
            // {
            //     return a;
            // }
            // else if (a.significand == 0 && b.significand == 0)
            // {
            //     return new HugeNum { significand = 0, exponent = 0 };
            // }

            // int sigExpoA = HugeNumHelper.Log10(a.significand);
            // int fullExpoA = a.exponent + sigExpoA;
            // int sigExpoB = HugeNumHelper.Log10(b.significand);
            // int fullExpoB = b.exponent + sigExpoB;

            // // 安全减法
            // if (fullExpoA >= 0 && fullExpoA <= 17 && a.exponent >= 0 && fullExpoB >= 0 && fullExpoB <= 17 && b.exponent >= 0)
            // {
            //     long va = a.significand * HugeNumHelper.POW_OF_10[a.exponent];
            //     long vb = b.significand * HugeNumHelper.POW_OF_10[b.exponent];
            //     return new HugeNum(va - vb);
            // }

            // double valueA = (double)a.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoA];
            // double valueB = (double)b.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoB];
            // int expDiff = fullExpoB - fullExpoA;

            // var ret = new HugeNum();
            // if (expDiff >= 18)
            // {
            //     // 加号两边数值相差太大
            //     ret.InitWith(-valueB * HugeNumHelper.EXP_17);
            //     ret.exponent += fullExpoA - 17 + expDiff;
            // }
            // else if (expDiff <= -18)
            // {
            //     ret.InitWith(valueA);
            //     ret.exponent += fullExpoA;
            // }
            // else
            // {
            //     // 精度损失严重(double有效位数为15-16)
            //     // 解决思路：考虑使用decimal；递归往下运算，一直运算到精度合理为止
            //     ret.InitWith(valueA - valueB * Math.Pow(10.0f, expDiff));
            //     ret.exponent += fullExpoA;
            // }
            // return ret;
        }

        public static HugeNum operator *(HugeNum a, HugeNum b)
        {
            if (a.IsZero() || b.IsZero())
            {
                return HugeNum.zero;
            }
            if (a.IsOne())
            {
                return b;
            }
            if (b.IsOne())
            {
                return a;
            }
            double dv = (double)a.significand * (double)b.significand;
            HugeNum result = HugeNum.zero;
            result.InitWith(dv);
            result.exponent += a.exponent + b.exponent;
            return result;

            /*
            if (0 == a.significand || 0 == b.significand)
            {
                return new HugeNum { significand = 0, exponent = 0 };
            }
            int sigExpoA = HugeNumHelper.Log10(a.significand);
            int fullExpoA = a.exponent + sigExpoA;
            int sigExpoB = HugeNumHelper.Log10(b.significand);
            int fullExpoB = b.exponent + sigExpoB;

            var valueA = (double)a.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoA];
            var valueB = (double)b.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoB];

            var ret = new HugeNum();
            ret.InitWith(valueA * valueB);
            ret.exponent += fullExpoA + fullExpoB;
            return ret;
            */
        }

        public static HugeNum operator /(HugeNum a, HugeNum b)
        {
            /*
            if (0L == a.significand || 0L == b.significand)
            {
                return new HugeNum { significand = 0, exponent = 0 };
            }
            int sigExpoA = HugeNumHelper.Log10(a.significand);
            int fullExpoA = a.exponent + sigExpoA;
            int sigExpoB = HugeNumHelper.Log10(b.significand);
            int fullExpoB = b.exponent + sigExpoB;

            var valueA = (double)a.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoA];
            var valueB = (double)b.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoB];

            var ret = new HugeNum();
            ret.InitWith(valueA / valueB);
            ret.exponent += fullExpoA - fullExpoB;
            return ret;
            */
            if (a.IsZero())
                return HugeNum.zero;
            if (b.IsZero())
                return new HugeNum(long.MaxValue, 300); // 除0不报错，会返回一个很大的数字
            double dv = (double)a.significand / (double)b.significand;
            HugeNum result = HugeNum.zero;
            result.InitWith(dv);
            result.exponent += a.exponent - b.exponent;
            return result;
        }

        public static float HugeRatio01(HugeNum cur, HugeNum curMax)
        {
            if (cur.TryGetFloat(out float a) && curMax.TryGetFloat(out float b))
            {
                var ratio = a / b;
                ratio = Mathf.Clamp01(ratio);
                return ratio;
            }
            else
            {
                var ratio = cur / curMax;
                if (ratio.TryGetFloat(out float r))
                {
                    r = Mathf.Clamp01(r);
                    return r;
                }
                else
                {
                    if (cur.IsZero() || cur.IsNegative() || curMax > cur)
                    {
                        return 0f;
                    }
                    else
                    {
                        return 1;
                    }
                }
            }
        }
        public static bool operator >(HugeNum a, HugeNum b)
        {
            // 符号不同的比较
            if (a.significand > 0 && b.significand < 0)
                return true;
            else if (a.significand < 0 && b.significand > 0)
                return false;
            if (0 == a.significand || 0 == b.significand)
                return a.significand > b.significand;

            // 先统一指数位，再比较尾数
            var sigExpoA = HugeNumHelper.Log10(a.significand);
            int fullExpoA = a.exponent + sigExpoA;
            var sigExpoB = HugeNumHelper.Log10(b.significand);
            int fullExpoB = b.exponent + sigExpoB;
            if (a.significand > 0)
            {
                // 正数比较
                if (fullExpoA > fullExpoB)
                    return true;
                else if (fullExpoA < fullExpoB)
                    return false;
                return (double)a.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoA]
                    > (double)b.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoB];
            }
            else
            {
                // 负数比较
                if (fullExpoA > fullExpoB)
                    return false;
                else if (fullExpoA < fullExpoB)
                    return true;
                return (double)a.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoA]
                    > (double)b.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoB];
            }
        }

        public static bool operator <(HugeNum a, HugeNum b)
        {
            // 符号不同的比较
            if (a.significand > 0 && b.significand < 0)
                return false;
            else if (a.significand < 0 && b.significand > 0)
                return true;
            if (0 == a.significand || 0 == b.significand)
                return a.significand < b.significand;

            // 先统一指数位，再比较尾数
            var sigExpoA = HugeNumHelper.Log10(a.significand);
            int fullExpoA = a.exponent + sigExpoA;
            var sigExpoB = HugeNumHelper.Log10(b.significand);
            int fullExpoB = b.exponent + sigExpoB;
            if (a.significand > 0)
            {
                // 正数比较
                if (fullExpoA > fullExpoB)
                    return false;
                else if (fullExpoA < fullExpoB)
                    return true;
                return (double)a.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoA]
                    < (double)b.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoB];
            }
            else
            {
                // 负数比较
                if (fullExpoA > fullExpoB)
                    return true;
                else if (fullExpoA < fullExpoB)
                    return false;
                return (double)a.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoA]
                    < (double)b.significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpoB];
            }
        }

        public static bool operator ==(HugeNum a, HugeNum b)
        {
            // zero
            if (a.significand == b.significand && a.significand == 0)
                return true;
            if (0 == a.significand && 0 != b.significand)
                return false;
            if (0 != a.significand && 0 == b.significand)
                return false;
            if (a.exponent == b.exponent)
            {
                return a.significand == b.significand;
            }
            else
            {
                int sigExpoA = HugeNumHelper.Log10(a.significand);
                int fullExpoA = a.exponent + sigExpoA;
                int sigExpoB = HugeNumHelper.Log10(b.significand);
                int fullExpoB = b.exponent + sigExpoB;
                // 先统一指数位，再比较尾数
                if (fullExpoA != fullExpoB)
                {
                    return false;
                }
                // 浮点数相等判断有误差
                // return a.significand / HugeNumHelper.EXP_TO_VAL[sigExpoA]
                //     == b.significand / HugeNumHelper.EXP_TO_VAL[sigExpoB];

                long sigA;
                long sigB;
                int expA;
                int expB;
                // 有效位调整到同一指数位置
                if (sigExpoA >= sigExpoB)
                {
                    sigA = a.significand;
                    expA = a.exponent;
                    int delta = sigExpoA - sigExpoB;
                    sigB = b.significand * HugeNumHelper.POW_OF_10[delta];
                    expB = b.exponent - delta;
                }
                else
                {
                    sigB = b.significand;
                    expB = b.exponent;
                    int delta = sigExpoB - sigExpoA;
                    sigA = a.significand * HugeNumHelper.POW_OF_10[delta];
                    expA = a.exponent - delta;
                }
                return sigA == sigB && expA == expB;
            }
        }

        public static bool operator >=(HugeNum a, HugeNum b)
        {
            return a > b || a == b;
        }

        public static bool operator <=(HugeNum a, HugeNum b)
        {
            return a < b || a == b;
        }

        public static bool operator !=(HugeNum a, HugeNum b)
        {
            return !(a == b);
        }

        private static HugeNum Add(HugeNum a, HugeNum b, int level, out bool changed)
        {
            changed = false;
            return HugeNum.zero;
        }

        /// <summary>
        ///   加法, 如果两数相差太大，可能加不上，此时changed=false
        ///   aX10^m + bX10^n --> (a + b * 10^(n - m)) * 10^m 
        /// </summary>
        public static HugeNum Add(HugeNum a, HugeNum b, out bool changed)
        {
            if (a.IsZero())
            {
                changed = true;
                return b;
            }
            if (b.IsZero())
            {
                changed = true;
                return a;
            }

            int sigExpA = HugeNumHelper.Log10(a.significand);
            int fullExpA = a.exponent + sigExpA;
            int sigExpB = HugeNumHelper.Log10(b.significand);
            int fullExpB = b.exponent + sigExpB;

            if (
                fullExpA >= 0 && fullExpA <= 16 &&
                fullExpB >= 0 && fullExpB <= 16
                )
            {
                changed = true;
                if (a.exponent >= 0 && b.exponent >= 0)
                {
                    // 加法运算不超过long型的有效范围, 指数不为负，运算无精度损失
                    long va = a.significand * HugeNumHelper.POW_OF_10[a.exponent];
                    long vb = b.significand * HugeNumHelper.POW_OF_10[b.exponent];
                    return new HugeNum(va + vb, 0);
                }
                else
                {
                    // 加法运算不超过long型的有效范围, 指数有负数，运算有精度损失
                    double va;
                    double vb;
                    if (a.exponent < 0)
                    {
                        va = (double)a.significand / (double)HugeNumHelper.POW_OF_10[-a.exponent];
                    }
                    else
                    {
                        va = a.significand * HugeNumHelper.POW_OF_10[a.exponent];
                    }
                    if (b.exponent < 0)
                    {
                        vb = (double)b.significand / (double)HugeNumHelper.POW_OF_10[-b.exponent];
                    }
                    else
                    {
                        vb = b.significand * HugeNumHelper.POW_OF_10[b.exponent];
                    }
                    return new HugeNum(va + vb);
                }
            }
            else if (
                     fullExpA >= -16 && fullExpA <= 16 &&
                     fullExpB >= -16 && fullExpB <= 16
                     )
            {
                // 加法运算不超过long型的有效范围
                double va = a.significand * Math.Pow(10.0, a.exponent);
                double vb = b.significand * Math.Pow(10.0, b.exponent);
                changed = true;
                return new HugeNum(va + vb);
            }

            // throw new NotImplementedException();

            long expDiff = (long)b.exponent - (long)a.exponent;

            long tmp = (long)sigExpB + expDiff;
            if (tmp >= -300 && tmp <= 300)
            {
                changed = true;
                double v = a.significand + b.significand * Math.Pow(10.0, expDiff);
                HugeNum result = HugeNum.zero;
                result.InitWith(v);
                result.exponent += a.exponent;
                return result;
            }
            else if (tmp > 300)
            {
                // 加法失败，取右侧
                changed = false;
                HugeNum result = new HugeNum(b.significand, (int)expDiff);
                result.exponent += a.exponent;
                return result;
            }
            else
            {
                // 加法失败，取左侧
                changed = false;
                return a;
            }

            // // TODO: 
            // changed = false;
            // if (a.significand == 0)
            // {
            //     return b;
            // }
            // else if (b.significand == 0)
            // {
            //     return a;
            // }
            // return a + b;
        }

        /// <summary>
        ///   减法, 如果两数相差太大，可能减不上，此时changed=false
        /// </summary>
        public static HugeNum Subtract(HugeNum a, HugeNum b, out bool changed)
        {
            // // TODO: 
            // changed = false;
            // return a - b;
            return Add(a, b.Negate(), out changed);
        }

        #endregion

        public override bool Equals(object obj)
        {
            if (obj is HugeNum)
            {
                return this == (HugeNum)obj;
            }
            return false;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        ///    /*规则修改，去除k单位*/ 添加 k 单位
        /// </summary>
        public override string ToString()
        {
            // if (significand == 0L)
            // {
            //     return "0";
            // }
            //if (0 == exponent && significand < 1000000L)
            //{
            //    // Console.WriteLine("is small long");
            //    return significand.ToString();
            //}

            long longVal;
            if (HugeNumHelper.ChineseSymbol)
            {
                if (ToLong(out longVal) && longVal < 10000L && longVal > -10000L/*000L*/)
                {
                    // Console.WriteLine("is small long 2");
                    return longVal.ToString();
                }
            }
            else
            {
                if (ToLong(out longVal) && longVal < 1000L && longVal > -1000L/*000L*/)
                {
                    // Console.WriteLine("is small long 2");
                    return longVal.ToString();
                }
            }


            float floatValue;
            if (TryGetFloat(out floatValue))
            {
                if (HugeNumHelper.ChineseSymbol)
                {
                    if (floatValue > -10000.0f && floatValue < 10000.0f)
                    {
                        // Console.WriteLine("is float: {0}", floatValue);
                        // return floatValue.ToString("0.###");
                        return UnityEngine.Mathf.CeilToInt(floatValue).ToString();
                    }
                }
                else
                {
                    if (floatValue > -1000.0f && floatValue < 1000.0f)
                    {
                        // Console.WriteLine("is float: {0}", floatValue);
                        // return floatValue.ToString("0.###");
                        return UnityEngine.Mathf.CeilToInt(floatValue).ToString();
                    }
                }

                // else if (floatValue >/*= -1000000.0f*/-1000.0f && floatValue </*= 1000000.0f*/1000.0f)
                // {
                //     // var tmp = floatValue.ToString("0.###");
                //     var tmp = floatValue.ToString("0.#");
                //     // 最多显示6个数字
                //     int n = tmp.Length;
                //     if (n > 7)
                //     {
                //         // 截断
                //         tmp = tmp.Substring(0, 7);
                //         if (tmp.EndsWith("."))
                //         {
                //             tmp = tmp.Substring(0, tmp.Length - 1);
                //         }
                //         return tmp;
                //     }
                //     else
                //     {
                //         return tmp;
                //     }
                // }
            }

            var log10Sig = HugeNumHelper.Log10(significand);
            // 重新计算指数位
            var expo_ = exponent + log10Sig;

            var normalizedSignificand = (double)significand / (double)HugeNumHelper.EXP_TO_VAL[log10Sig];

            string suffix = ""; // 后缀
            string numStr = ""; // 数字部分
            int xyz = 0;

            if (expo_ > 0)
            {
                suffix = HugeNumHelper.ExponentToSuffix(expo_, out xyz);
            }

            if (expo_ < 0)
            {
                // 浮点数
                // numStr = (normalizedSignificand * Math.Pow(10.0, expo_)).ToString("0.###");
                numStr = (normalizedSignificand * Math.Pow(10.0, expo_)).ToString("F1");
            }
            else
            {
                if (0 == xyz)
                {
                    numStr = normalizedSignificand.ToString("0.#");
                    // numStr = normalizedSignificand.ToString("F3");
                }
                else if (1 == xyz)
                {
                    numStr = (normalizedSignificand * 10.0).ToString("0.#");
                    // numStr = (normalizedSignificand * 10.0).ToString("F3");
                }
                else if (2 == xyz)
                {
                    numStr = (normalizedSignificand * 100.0).ToString("0.#");
                    // numStr = (normalizedSignificand * 100.0).ToString("F3");
                }
                else if (3 == xyz)
                {
                    numStr = (normalizedSignificand * 1000.0).ToString("0.#");
                    // numStr = (normalizedSignificand * 100.0).ToString("F3");
                }
            }

            return numStr + suffix;
        }

        /// <summary>
        ///    /*规则修改，去除k单位*/ 添加 k 单位
        /// </summary>
        public string ToString(int num)
        {
            // if (significand == 0L)
            // {
            //     return "0";
            // }
            //if (0 == exponent && significand < 1000000L)
            //{
            //    // Console.WriteLine("is small long");
            //    return significand.ToString();
            //}

            long longVal;
            if (HugeNumHelper.ChineseSymbol)
            {
                if (ToLong(out longVal) && longVal < 10000L && longVal > -10000L/*000L*/)
                {
                    // Console.WriteLine("is small long 2");
                    return longVal.ToString();
                }
            }
            else
            {
                if (ToLong(out longVal) && longVal < 1000L && longVal > -1000L/*000L*/)
                {
                    // Console.WriteLine("is small long 2");
                    return longVal.ToString();
                }
            }


            float floatValue;
            if (TryGetFloat(out floatValue))
            {
                if (HugeNumHelper.ChineseSymbol)
                {
                    if (floatValue > -10000.0f && floatValue < 10000.0f)
                    {
                        // Console.WriteLine("is float: {0}", floatValue);
                        // return floatValue.ToString("0.###");
                        return UnityEngine.Mathf.CeilToInt(floatValue).ToString();
                    }
                }
                else
                {
                    if (floatValue > -1000.0f && floatValue < 1000.0f)
                    {
                        // Console.WriteLine("is float: {0}", floatValue);
                        // return floatValue.ToString("0.###");
                        return UnityEngine.Mathf.CeilToInt(floatValue).ToString();
                    }
                }

                // else if (floatValue >/*= -1000000.0f*/-1000.0f && floatValue </*= 1000000.0f*/1000.0f)
                // {
                //     // var tmp = floatValue.ToString("0.###");
                //     var tmp = floatValue.ToString("0.#");
                //     // 最多显示6个数字
                //     int n = tmp.Length;
                //     if (n > 7)
                //     {
                //         // 截断
                //         tmp = tmp.Substring(0, 7);
                //         if (tmp.EndsWith("."))
                //         {
                //             tmp = tmp.Substring(0, tmp.Length - 1);
                //         }
                //         return tmp;
                //     }
                //     else
                //     {
                //         return tmp;
                //     }
                // }
            }

            var log10Sig = HugeNumHelper.Log10(significand);
            // 重新计算指数位
            var expo_ = exponent + log10Sig;

            var normalizedSignificand = (double)significand / (double)HugeNumHelper.EXP_TO_VAL[log10Sig];

            string suffix = ""; // 后缀
            string numStr = ""; // 数字部分
            int xyz = 0;

            if (expo_ > 0)
            {
                suffix = HugeNumHelper.ExponentToSuffix(expo_, out xyz);
            }

            if (expo_ < 0)
            {
                // 浮点数
                // numStr = (normalizedSignificand * Math.Pow(10.0, expo_)).ToString("0.###");
                numStr = (normalizedSignificand * Math.Pow(10.0, expo_)).ToString("F0");
            }
            else
            {
                if (0 == xyz)
                {
                    numStr = normalizedSignificand.ToString("F0");
                    // numStr = normalizedSignificand.ToString("F3");
                }
                else if (1 == xyz)
                {
                    numStr = (normalizedSignificand * 10.0).ToString("F0");
                    // numStr = (normalizedSignificand * 10.0).ToString("F3");
                }
                else if (2 == xyz)
                {
                    numStr = (normalizedSignificand * 100.0).ToString("F0");
                    // numStr = (normalizedSignificand * 100.0).ToString("F3");
                }
                else if (3 == xyz)
                {
                    numStr = (normalizedSignificand * 1000.0).ToString("F0");
                    // numStr = (normalizedSignificand * 100.0).ToString("F3");
                }
            }

            return numStr + suffix;
        }


        public string ToTimer()
        {
            string ret = "";

            //HugeNum h=HugeNum/60*60*60

            return ret;
        }

        public HugeNum FromString(string s)
        {
            return new HugeNum(s);
        }

        public string DebugInfo()
        {
            // 科学记数法
            int sigExpo = HugeNumHelper.Log10(significand);
            int fullExpo = exponent + sigExpo;
            double num = (double)significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpo];
            string sci = string.Format("{0}E{1}", num.ToString(), fullExpo);
            string ret = string.Format("{{sig={0}, exp={1} sci={2}}}", significand.ToString(), exponent.ToString(), sci);
            return ret;
        }

        /// <summary>
        ///   科学记数法
        /// </summary>
        public string ScientificNotation()
        {
            int sigExpo = HugeNumHelper.Log10(significand);
            int fullExpo = exponent + sigExpo;
            double num = (double)significand / (double)HugeNumHelper.EXP_TO_VAL[sigExpo];
            string sci = string.Format("{0}E{1}", num.ToString(), fullExpo);
            return sci;
        }

        /// <summary>
        /// 显示详细数据样式，数值为整数最大数值 单位为最小单位   125135565as
        /// </summary>
        /// <returns></returns>
        public string ShowDetailNum()
        {
            // string ret = "";
            // ret = string.Format("n={0},u={1}", "", "");
            // return ret;
            return ScientificNotation();
        }

        /// <summary>
        /// 范围 在 [-1,1] 区间可获得float 值
        /// </summary>
        /// <param name="f"> float 值 </param>
        /// <returns>是否转换成功</returns>
        public bool TryGetFloat(out float f)
        {
            // max float: 3.402823E+38
            int sigExpo = HugeNumHelper.Log10(significand);
            int fullExpo = exponent + sigExpo;
            if (fullExpo >= -37 && fullExpo <= 37)
            {
                f = (float)(significand * Math.Pow(10.0, exponent));
                return true;
            }
            else
            {
                f = 0;
                return false;
            }
        }

        public bool ToLong(out long result)
        {
            if (0 == exponent)
            {
                result = significand;
                return true;
            }
            if (IsFloat())
            {
                result = 0;
                return false;
            }
            int sigExpo = HugeNumHelper.Log10(significand);
            int fullExpo = exponent + sigExpo;
            if (fullExpo >= 0 && fullExpo <= 17)
            {
                try
                {
                    // TODO: 添加无误差版本
                    result = checked((long)(significand * Math.Pow(10.0f, exponent)));
                    return true;
                }
                catch (OverflowException e)
                {
                    Console.WriteLine(e);
                }
            }
            result = 0L;
            return false;
        }

        /// <summary>
        ///   判断是否是小数
        /// </summary>
        public bool IsFloat()
        {
            if (0 == exponent)
                return false;
            int tailZeros = CountTailZeros(significand);
            if (tailZeros + exponent >= 0)
                return false;
            return true;
        }

        /// <summary>
        ///   向上取整
        /// </summary>
        public HugeNum Ceiling()
        {
            if (0 == significand || exponent >= 0)
                return this;
            int tailZeros = CountTailZeros(significand);
            if (tailZeros + exponent > 0)
                return this;
            int log10OfSig = HugeNumHelper.Log10(significand);
            int fullLog10 = log10OfSig + exponent;
            if (fullLog10 < 0)
            {
                // 0.xx小数
                if (significand > 0)
                    return HugeNum.one;
                else
                    return HugeNum.neg_one;
            }
            if (this < 1000)
            {
                double tmp = significand * Math.Pow(10, exponent);
                // return new HugeNum((long)tmp, 0);
                return new HugeNum((long)Math.Ceiling(tmp), 0);
            }
            else
            {
                return this;
            }
        }

        /// <summary>
        ///   向下取整
        /// </summary>
        public HugeNum Floor()
        {
            if (0 == significand || exponent >= 0)
                return this;
            int tailZeros = CountTailZeros(significand);
            if (tailZeros + exponent > 0)
                return this;
            int log10OfSig = HugeNumHelper.Log10(significand);
            int fullLog10 = log10OfSig + exponent;
            if (fullLog10 < 0)
            {
                return HugeNum.zero;
            }
            if (this < 1000)
            {
                double tmp = significand * Math.Pow(10, exponent);
                return new HugeNum((long)tmp, 0);
            }
            else
            {
                return this;
            }
        }

        /// <summary>
        ///   四舍五入
        /// </summary>
        public HugeNum Round()
        {
            return this.Ceiling();
        }

        public static HugeNum Ceiling(HugeNum v)
        {
            return v.Ceiling();
        }

        public static HugeNum Floor(HugeNum v)
        {
            return v.Floor();
        }

        /// <summary>
        ///   计算数字尾部有几个0
        /// </summary>
        public static int CountTailZeros(long value)
        {
            if (value >= -9L && value <= 9)
                return 0;
            int count = 0;
            int log10 = HugeNumHelper.Log10(value);
            long k = 10;
            for (int i = 0; i < log10; i++)
            {
                if (value % k == 0)
                {
                    count++;
                    k *= 10L;
                }
                else
                {
                    break;
                }
            }
            return count;
        }

        /// <summary>
        ///   转换为整数(小数部分截断)
        /// </summary>
        // public void ToInteger()
        // {
        //     if (0L == significand)
        //         return;
        //     int sigExpo = HugeNumHelper.Log10(significand);
        //     if (exponent < 0 && -exponent > sigExpo)
        //     {
        //     }
        // }

        /// <summary>
        ///   获得整数形式
        /// </summary>
        // public HugeNum GetInteger()
        // {
        //     var ret = this;
        //     ret.ToInteger();
        //     return ret;
        // }


        public static HugeNum Parse(string s)
        {
            if (s.Contains(","))
            {
                string[] ints = s.Split(',');
                HugeNum speed = new HugeNum(long.Parse(ints[0]), int.Parse(ints[1]));
                return speed;
            }
            else
            {
                return new HugeNum(s);
            }
        }


        public const long precision_k = 1000;
        public const long precision_m = 1000000;
        public const long precision_b = 1000000000;
        public const long precision_t = 1000000000000;


        public long ReducePrecision(long significand, int exponent)
        {
            // 策划决定：可以舍弃看不到的位，如22.3k = 223000, 所以取余舍去，测试在TestHugeNum 场景中
            // hotfix: 100 = 0.1k
            if (exponent == -4)
                return significand;
            var ext = exponent == -4 ? 10000 : 1;
            var signOrigin = significand / ext;
            if (signOrigin > 0)
            {
                if (signOrigin >= precision_k && signOrigin < precision_m)
                    signOrigin = signOrigin - signOrigin % (precision_k / 10);
                if (signOrigin >= precision_m && signOrigin < precision_b)
                    signOrigin = signOrigin - signOrigin % (precision_m / 10);
                if (signOrigin >= precision_b && signOrigin < precision_t)
                    signOrigin = signOrigin - signOrigin % (precision_b / 10);
                if (signOrigin >= precision_t)
                    signOrigin = signOrigin - signOrigin % (precision_t / 10);
            }
            else if (signOrigin < 0)
            {
                if (signOrigin <= -precision_k && signOrigin > -precision_m)
                    signOrigin = signOrigin - signOrigin % (-precision_k / 10);
                if (signOrigin <= -precision_m && signOrigin > -precision_b)
                    signOrigin = signOrigin - signOrigin % (-precision_m / 10);
                if (signOrigin <= -precision_b && signOrigin > -precision_t)
                    signOrigin = signOrigin - signOrigin % (-precision_b / 10);
                if (signOrigin <= -precision_t)
                    signOrigin = signOrigin - signOrigin % (-precision_t / 10);
            }

            return signOrigin * ext;
        }
    }
}
